home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Common / src / d3dfont.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  23.2 KB  |  675 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DFont.cpp
  3. //
  4. // Desc: Texture-based font class
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <stdio.h>
  10. #include <tchar.h>
  11. #include <D3DX8.h>
  12. #include "D3DFont.h"
  13. #include "D3DUtil.h"
  14. #include "DXUtil.h"
  15.  
  16.  
  17.  
  18.  
  19. //-----------------------------------------------------------------------------
  20. // Custom vertex types for rendering text
  21. //-----------------------------------------------------------------------------
  22. #define MAX_NUM_VERTICES 50*6
  23.  
  24. struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
  25. struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };
  26.  
  27. #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  28. #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  29.  
  30. inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
  31.                                       FLOAT tu, FLOAT tv )
  32. {
  33.     FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
  34.     return v;
  35. }
  36.  
  37. inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
  38.                                       FLOAT tu, FLOAT tv )
  39. {
  40.     FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
  41.     return v;
  42. }
  43.  
  44.  
  45.  
  46.  
  47. //-----------------------------------------------------------------------------
  48. // Name: CD3DFont()
  49. // Desc: Font class constructor
  50. //-----------------------------------------------------------------------------
  51. CD3DFont::CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
  52. {
  53.     _tcscpy( m_strFontName, strFontName );
  54.     m_dwFontHeight         = dwHeight;
  55.     m_dwFontFlags          = dwFlags;
  56.  
  57.     m_pd3dDevice           = NULL;
  58.     m_pTexture             = NULL;
  59.     m_pVB                  = NULL;
  60.  
  61.     m_dwSavedStateBlock    = 0L;
  62.     m_dwDrawTextStateBlock = 0L;
  63. }
  64.  
  65.  
  66.  
  67.  
  68. //-----------------------------------------------------------------------------
  69. // Name: ~CD3DFont()
  70. // Desc: Font class destructor
  71. //-----------------------------------------------------------------------------
  72. CD3DFont::~CD3DFont()
  73. {
  74.     InvalidateDeviceObjects();
  75.     DeleteDeviceObjects();
  76. }
  77.  
  78.  
  79.  
  80.  
  81. //-----------------------------------------------------------------------------
  82. // Name: InitDeviceObjects()
  83. // Desc: Initializes device-dependent objects, including the vertex buffer used
  84. //       for rendering text and the texture map which stores the font image.
  85. //-----------------------------------------------------------------------------
  86. HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE8 pd3dDevice )
  87. {
  88.     HRESULT hr;
  89.  
  90.     // Keep a local copy of the device
  91.     m_pd3dDevice = pd3dDevice;
  92.  
  93.     // Establish the font and texture size
  94.     m_fTextScale  = 1.0f; // Draw fonts into texture without scaling
  95.  
  96.     // Large fonts need larger textures
  97.     if( m_dwFontHeight > 40 )
  98.         m_dwTexWidth = m_dwTexHeight = 1024;
  99.     else if( m_dwFontHeight > 20 )
  100.         m_dwTexWidth = m_dwTexHeight = 512;
  101.     else
  102.         m_dwTexWidth  = m_dwTexHeight = 256;
  103.  
  104.     // If requested texture is too big, use a smaller texture and smaller font,
  105.     // and scale up when rendering.
  106.     D3DCAPS8 d3dCaps;
  107.     m_pd3dDevice->GetDeviceCaps( &d3dCaps );
  108.  
  109.     if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
  110.     {
  111.         m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
  112.         m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
  113.     }
  114.  
  115.     // Create a new texture for the font
  116.     hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
  117.                                       0, D3DFMT_A4R4G4B4,
  118.                                       D3DPOOL_MANAGED, &m_pTexture );
  119.     if( FAILED(hr) )
  120.         return hr;
  121.  
  122.     // Prepare to create a bitmap
  123.     DWORD*      pBitmapBits;
  124.     BITMAPINFO bmi;
  125.     ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
  126.     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  127.     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
  128.     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
  129.     bmi.bmiHeader.biPlanes      = 1;
  130.     bmi.bmiHeader.biCompression = BI_RGB;
  131.     bmi.bmiHeader.biBitCount    = 32;
  132.  
  133.     // Create a DC and a bitmap for the font
  134.     HDC     hDC       = CreateCompatibleDC( NULL );
  135.     HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
  136.                                           (VOID**)&pBitmapBits, NULL, 0 );
  137.     SetMapMode( hDC, MM_TEXT );
  138.  
  139.     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
  140.     // antialiased font, but this is not guaranteed.
  141.     INT nHeight    = -MulDiv( m_dwFontHeight, 
  142.         (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
  143.     DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
  144.     DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
  145.     HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
  146.                           FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  147.                           CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
  148.                           VARIABLE_PITCH, m_strFontName );
  149.     if( NULL==hFont )
  150.         return E_FAIL;
  151.  
  152.     SelectObject( hDC, hbmBitmap );
  153.     SelectObject( hDC, hFont );
  154.  
  155.     // Set text properties
  156.     SetTextColor( hDC, RGB(255,255,255) );
  157.     SetBkColor(   hDC, 0x00000000 );
  158.     SetTextAlign( hDC, TA_TOP );
  159.  
  160.     // Loop through all printable character and output them to the bitmap..
  161.     // Meanwhile, keep track of the corresponding tex coords for each character.
  162.     DWORD x = 0;
  163.     DWORD y = 0;
  164.     TCHAR str[2] = _T("x");
  165.     SIZE size;
  166.  
  167.     for( TCHAR c=32; c<127; c++ )
  168.     {
  169.         str[0] = c;
  170.         GetTextExtentPoint32( hDC, str, 1, &size );
  171.  
  172.         if( (DWORD)(x+size.cx+1) > m_dwTexWidth )
  173.         {
  174.             x  = 0;
  175.             y += size.cy+1;
  176.         }
  177.  
  178.         ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
  179.  
  180.         m_fTexCoords[c-32][0] = ((FLOAT)(x+0))/m_dwTexWidth;
  181.         m_fTexCoords[c-32][1] = ((FLOAT)(y+0))/m_dwTexHeight;
  182.         m_fTexCoords[c-32][2] = ((FLOAT)(x+0+size.cx))/m_dwTexWidth;
  183.         m_fTexCoords[c-32][3] = ((FLOAT)(y+0+size.cy))/m_dwTexHeight;
  184.  
  185.         x += size.cx+1;
  186.     }
  187.  
  188.     // Lock the surface and write the alpha values for the set pixels
  189.     D3DLOCKED_RECT d3dlr;
  190.     m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
  191.     BYTE* pDstRow = (BYTE*)d3dlr.pBits;
  192.     WORD* pDst16;
  193.     BYTE bAlpha; // 4-bit measure of pixel intensity
  194.  
  195.     for( y=0; y < m_dwTexHeight; y++ )
  196.     {
  197.         pDst16 = (WORD*)pDstRow;
  198.         for( x=0; x < m_dwTexWidth; x++ )
  199.         {
  200.             bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
  201.             if (bAlpha > 0)
  202.             {
  203.                 *pDst16++ = (bAlpha << 12) | 0x0fff;
  204.             }
  205.             else
  206.             {
  207.                 *pDst16++ = 0x0000;
  208.             }
  209.         }
  210.         pDstRow += d3dlr.Pitch;
  211.     }
  212.  
  213.     // Done updating texture, so clean up used objects
  214.     m_pTexture->UnlockRect(0);
  215.     DeleteObject( hbmBitmap );
  216.     DeleteDC( hDC );
  217.     DeleteObject( hFont );
  218.  
  219.     return S_OK;
  220. }
  221.  
  222.  
  223.  
  224.  
  225. //-----------------------------------------------------------------------------
  226. // Name: RestoreDeviceObjects()
  227. // Desc:
  228. //-----------------------------------------------------------------------------
  229. HRESULT CD3DFont::RestoreDeviceObjects()
  230. {
  231.     HRESULT hr;
  232.  
  233.     // Create vertex buffer for the letters
  234.     if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES*sizeof(FONT2DVERTEX),
  235.                                                        D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
  236.                                                        D3DPOOL_DEFAULT, &m_pVB ) ) )
  237.     {
  238.         return hr;
  239.     }
  240.  
  241.     // Create the state blocks for rendering text
  242.     for( UINT which=0; which<2; which++ )
  243.     {
  244.         m_pd3dDevice->BeginStateBlock();
  245.         m_pd3dDevice->SetTexture( 0, m_pTexture );
  246.  
  247.         if ( D3DFONT_ZENABLE & m_dwFontFlags )
  248.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  249.         else
  250.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  251.  
  252.         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  253.         m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
  254.         m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
  255.         m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
  256.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
  257.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
  258.         m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
  259.         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
  260.         m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
  261.         m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
  262.         m_pd3dDevice->SetRenderState( D3DRS_EDGEANTIALIAS,    FALSE );
  263.         m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
  264.         m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      FALSE );
  265.         m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
  266.         m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
  267.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  268.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  269.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  270.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  271.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  272.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  273.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  274.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  275.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE );
  276.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
  277.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
  278.         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  279.         m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  280.  
  281.         if( which==0 )
  282.             m_pd3dDevice->EndStateBlock( &m_dwSavedStateBlock );
  283.         else
  284.             m_pd3dDevice->EndStateBlock( &m_dwDrawTextStateBlock );
  285.     }
  286.  
  287.     return S_OK;
  288. }
  289.  
  290.  
  291.  
  292.  
  293. //-----------------------------------------------------------------------------
  294. // Name: InvalidateDeviceObjects()
  295. // Desc: Destroys all device-dependent objects
  296. //-----------------------------------------------------------------------------
  297. HRESULT CD3DFont::InvalidateDeviceObjects()
  298. {
  299.     SAFE_RELEASE( m_pVB );
  300.  
  301.     // Delete the state blocks
  302.     if( m_pd3dDevice )
  303.     {
  304.         if( m_dwSavedStateBlock )
  305.             m_pd3dDevice->DeleteStateBlock( m_dwSavedStateBlock );
  306.         if( m_dwDrawTextStateBlock )
  307.             m_pd3dDevice->DeleteStateBlock( m_dwDrawTextStateBlock );
  308.     }
  309.  
  310.     m_dwSavedStateBlock    = 0L;
  311.     m_dwDrawTextStateBlock = 0L;
  312.  
  313.     return S_OK;
  314. }
  315.  
  316.  
  317.  
  318.  
  319. //-----------------------------------------------------------------------------
  320. // Name: DeleteDeviceObjects()
  321. // Desc: Destroys all device-dependent objects
  322. //-----------------------------------------------------------------------------
  323. HRESULT CD3DFont::DeleteDeviceObjects()
  324. {
  325.     SAFE_RELEASE( m_pTexture );
  326.     m_pd3dDevice = NULL;
  327.  
  328.     return S_OK;
  329. }
  330.  
  331.  
  332.  
  333.  
  334. //-----------------------------------------------------------------------------
  335. // Name: GetTextExtent()
  336. // Desc: Get the dimensions of a text string
  337. //-----------------------------------------------------------------------------
  338. HRESULT CD3DFont::GetTextExtent( TCHAR* strText, SIZE* pSize )
  339. {
  340.     if( NULL==strText || NULL==pSize )
  341.         return E_FAIL;
  342.  
  343.     FLOAT fRowWidth  = 0.0f;
  344.     FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  345.     FLOAT fWidth     = 0.0f;
  346.     FLOAT fHeight    = fRowHeight;
  347.  
  348.     while( *strText )
  349.     {
  350.         TCHAR c = *strText++;
  351.  
  352.         if( c == _T('\n') )
  353.         {
  354.             fRowWidth = 0.0f;
  355.             fHeight  += fRowHeight;
  356.         }
  357.         if( c < _T(' ') )
  358.             continue;
  359.  
  360.         FLOAT tx1 = m_fTexCoords[c-32][0];
  361.         FLOAT tx2 = m_fTexCoords[c-32][2];
  362.  
  363.         fRowWidth += (tx2-tx1)*m_dwTexWidth;
  364.  
  365.         if( fRowWidth > fWidth )
  366.             fWidth = fRowWidth;
  367.     }
  368.  
  369.     pSize->cx = (int)fWidth;
  370.     pSize->cy = (int)fHeight;
  371.  
  372.     return S_OK;
  373. }
  374.  
  375.  
  376.  
  377.  
  378. //-----------------------------------------------------------------------------
  379. // Name: DrawTextScaled()
  380. // Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates
  381. //       (ranging from -1 to +1).  fXScale and fYScale are the size fraction 
  382. //       relative to the entire viewport.  For example, a fXScale of 0.25 is
  383. //       1/8th of the screen width.  This allows you to output text at a fixed
  384. //       fraction of the viewport, even if the screen or window size changes.
  385. //-----------------------------------------------------------------------------
  386. HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
  387.                                   FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
  388.                                   TCHAR* strText, DWORD dwFlags )
  389. {
  390.     if( m_pd3dDevice == NULL )
  391.         return E_FAIL;
  392.  
  393.     // Set up renderstate
  394.     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
  395.     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
  396.     m_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX );
  397.     m_pd3dDevice->SetPixelShader( NULL );
  398.     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT2DVERTEX) );
  399.  
  400.     // Set filter states
  401.     if( dwFlags & D3DFONT_FILTERED )
  402.     {
  403.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  404.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  405.     }
  406.  
  407.     D3DVIEWPORT8 vp;
  408.     m_pd3dDevice->GetViewport( &vp );
  409.     FLOAT sx  = (x+1.0f)*vp.Width/2;
  410.     FLOAT sy  = (y+1.0f)*vp.Height/2;
  411.     FLOAT sz  = z;
  412.     FLOAT rhw = 1.0f;
  413.     FLOAT fStartX = sx;
  414.  
  415.     FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
  416.  
  417.     // Fill vertex buffer
  418.     FONT2DVERTEX* pVertices;
  419.     DWORD         dwNumTriangles = 0L;
  420.     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
  421.  
  422.     while( *strText )
  423.     {
  424.         TCHAR c = *strText++;
  425.  
  426.         if( c == _T('\n') )
  427.         {
  428.             sx  = fStartX;
  429.             sy += fYScale*vp.Height;
  430.         }
  431.         if( c < _T(' ') )
  432.             continue;
  433.  
  434.         FLOAT tx1 = m_fTexCoords[c-32][0];
  435.         FLOAT ty1 = m_fTexCoords[c-32][1];
  436.         FLOAT tx2 = m_fTexCoords[c-32][2];
  437.         FLOAT ty2 = m_fTexCoords[c-32][3];
  438.  
  439.         FLOAT w = (tx2-tx1)*m_dwTexWidth;
  440.         FLOAT h = (ty2-ty1)*m_dwTexHeight;
  441.  
  442.         w *= (fXScale*vp.Width)/fLineHeight;
  443.         h *= (fYScale*vp.Height)/fLineHeight;
  444.  
  445.         if( c != _T(' ') )
  446.         {
  447.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
  448.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  449.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  450.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
  451.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
  452.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
  453.             dwNumTriangles += 2;
  454.  
  455.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  456.             {
  457.                 // Unlock, render, and relock the vertex buffer
  458.                 m_pVB->Unlock();
  459.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  460.                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
  461.                 dwNumTriangles = 0L;
  462.             }
  463.         }
  464.  
  465.         sx += w;
  466.     }
  467.  
  468.     // Unlock and render the vertex buffer
  469.     m_pVB->Unlock();
  470.     if( dwNumTriangles > 0 )
  471.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  472.  
  473.     // Restore the modified renderstates
  474.     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
  475.  
  476.     return S_OK;
  477. }
  478.  
  479.  
  480.  
  481.  
  482. //-----------------------------------------------------------------------------
  483. // Name: DrawText()
  484. // Desc: Draws 2D text
  485. //-----------------------------------------------------------------------------
  486. HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
  487.                             TCHAR* strText, DWORD dwFlags )
  488. {
  489.     if( m_pd3dDevice == NULL )
  490.         return E_FAIL;
  491.  
  492.     // Setup renderstate
  493.     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
  494.     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
  495.     m_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX );
  496.     m_pd3dDevice->SetPixelShader( NULL );
  497.     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT2DVERTEX) );
  498.  
  499.     // Set filter states
  500.     if( dwFlags & D3DFONT_FILTERED )
  501.     {
  502.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  503.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  504.     }
  505.  
  506.     FLOAT fStartX = sx;
  507.  
  508.     // Fill vertex buffer
  509.     FONT2DVERTEX* pVertices = NULL;
  510.     DWORD         dwNumTriangles = 0;
  511.     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
  512.  
  513.     while( *strText )
  514.     {
  515.         TCHAR c = *strText++;
  516.  
  517.         if( c == _T('\n') )
  518.         {
  519.             sx = fStartX;
  520.             sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  521.         }
  522.         if( c < _T(' ') )
  523.             continue;
  524.  
  525.         FLOAT tx1 = m_fTexCoords[c-32][0];
  526.         FLOAT ty1 = m_fTexCoords[c-32][1];
  527.         FLOAT tx2 = m_fTexCoords[c-32][2];
  528.         FLOAT ty2 = m_fTexCoords[c-32][3];
  529.  
  530.         FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
  531.         FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
  532.  
  533.         if( c != _T(' ') )
  534.         {
  535.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
  536.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  537.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  538.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
  539.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
  540.             *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
  541.             dwNumTriangles += 2;
  542.  
  543.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  544.             {
  545.                 // Unlock, render, and relock the vertex buffer
  546.                 m_pVB->Unlock();
  547.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  548.                 pVertices = NULL;
  549.                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
  550.                 dwNumTriangles = 0L;
  551.             }
  552.         }
  553.  
  554.         sx += w;
  555.     }
  556.  
  557.     // Unlock and render the vertex buffer
  558.     m_pVB->Unlock();
  559.     if( dwNumTriangles > 0 )
  560.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  561.  
  562.     // Restore the modified renderstates
  563.     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
  564.  
  565.     return S_OK;
  566. }
  567.  
  568.  
  569.  
  570.  
  571. //-----------------------------------------------------------------------------
  572. // Name: Render3DText()
  573. // Desc: Renders 3D text
  574. //-----------------------------------------------------------------------------
  575. HRESULT CD3DFont::Render3DText( TCHAR* strText, DWORD dwFlags )
  576. {
  577.     if( m_pd3dDevice == NULL )
  578.         return E_FAIL;
  579.  
  580.     // Setup renderstate
  581.     m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
  582.     m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
  583.     m_pd3dDevice->SetVertexShader( D3DFVF_FONT3DVERTEX );
  584.     m_pd3dDevice->SetPixelShader( NULL );
  585.     m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT3DVERTEX) );
  586.  
  587.     // Set filter states
  588.     if( dwFlags & D3DFONT_FILTERED )
  589.     {
  590.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  591.         m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  592.     }
  593.  
  594.     // Position for each text element
  595.     FLOAT x = 0.0f;
  596.     FLOAT y = 0.0f;
  597.  
  598.     // Center the text block at the origin
  599.     if( dwFlags & D3DFONT_CENTERED )
  600.     {
  601.         SIZE sz;
  602.         GetTextExtent( strText, &sz );
  603.         x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
  604.         y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
  605.     }
  606.  
  607.     // Turn off culling for two-sided text
  608.     if( dwFlags & D3DFONT_TWOSIDED )
  609.         m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  610.  
  611.     FLOAT fStartX = x;
  612.     TCHAR c;
  613.  
  614.     // Fill vertex buffer
  615.     FONT3DVERTEX* pVertices;
  616.     DWORD         dwVertex       = 0L;
  617.     DWORD         dwNumTriangles = 0L;
  618.     m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
  619.  
  620.     while( c = *strText++ )
  621.     {
  622.         if( c == '\n' )
  623.         {
  624.             x = fStartX;
  625.             y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
  626.         }
  627.         if( c < 32 )
  628.             continue;
  629.  
  630.         FLOAT tx1 = m_fTexCoords[c-32][0];
  631.         FLOAT ty1 = m_fTexCoords[c-32][1];
  632.         FLOAT tx2 = m_fTexCoords[c-32][2];
  633.         FLOAT ty2 = m_fTexCoords[c-32][3];
  634.  
  635.         FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );
  636.         FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
  637.  
  638.         if( c != _T(' ') )
  639.         {
  640.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
  641.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  642.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  643.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
  644.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
  645.             *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
  646.             dwNumTriangles += 2;
  647.  
  648.             if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
  649.             {
  650.                 // Unlock, render, and relock the vertex buffer
  651.                 m_pVB->Unlock();
  652.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  653.                 m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD );
  654.                 dwNumTriangles = 0L;
  655.             }
  656.         }
  657.  
  658.         x += w;
  659.     }
  660.  
  661.     // Unlock and render the vertex buffer
  662.     m_pVB->Unlock();
  663.     if( dwNumTriangles > 0 )
  664.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
  665.  
  666.     // Restore the modified renderstates
  667.     m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
  668.  
  669.     return S_OK;
  670. }
  671.  
  672.  
  673.  
  674.  
  675.